#include "luaanalyzer.h"
#include "common.h"
#include "cjson.h"

#include <locale>
#include <codecvt>

initialiseSingleton(LuaAnalyzer);

std::vector<std::string> ObjectInfo::getAllParamName(int type)
{
    std::vector<std::string> returnParams;

    if(type == 0)
    {
        for(int i=0;i<functions.size();i++)
            returnParams.push_back(functions[i].name);
    }
    else if(type == 1)
    {
        //for(int i=0;i<functions.size();i++)
        //    returnParams.push_back(functions[i].name);

        for(int i=0;i<params.size();i++)
            returnParams.push_back(params[i].name);
    }

    return returnParams;
}

LuaAnalyzer::LuaAnalyzer()
{

}

LuaAnalyzer::~LuaAnalyzer()
{

}

// Load Lua script from file
bool LuaAnalyzer::loadScript(const std::string& filePath)
{
    std::ifstream file(filePath);
    if (!file.is_open()) {
        return false;
    }

    scriptContent.clear();
    std::string line;
    while (std::getline(file, line)) {
        scriptContent.push_back(line);
    }
    file.close();
    return true;
}

bool LuaAnalyzer::loadGrammarNotes(const std::string& filePath)
{
    wxFile file(filePath);
    if (!file.IsOpened()) return false;

    wxCSConv gb2312Conv(wxFONTENCODING_UTF8);
    char* buffer = (char*)allocBytes(file.Length() + 1);
    file.Read(buffer, file.Length());
    buffer[file.Length()] = '\0';

    wxString content(buffer, gb2312Conv);

    deallocBytes(buffer);
    file.Close();

    using convert_type = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_type, wchar_t> converter;
    std::string resultContent = converter.to_bytes(content.wc_str());

    cJSON* root = cJSON_Parse(resultContent.c_str());
    if (!root) {
        return false;
    }

    // 获取 "对象" 数组
    cJSON* objects = cJSON_GetObjectItem(root, "对象");
    if (objects && cJSON_IsArray(objects)) {
        for (int i = 0; i < cJSON_GetArraySize(objects); i++) {
            cJSON* objItem = cJSON_GetArrayItem(objects, i);
            if (!objItem) continue;

            ObjectInfo oinfo;

            // 解析对象名称
            cJSON* objname = cJSON_GetObjectItem(objItem, "名称");
            if (objname && cJSON_IsString(objname)) {
                oinfo.objectName = objname->valuestring;
            }

            cJSON* createfunction = cJSON_GetObjectItem(objItem, "创建函数");
            if (createfunction && cJSON_IsString(createfunction)) {
                oinfo.createfunction = SplitString2(createfunction->valuestring,'|');
            }

            cJSON* inheritedclass = cJSON_GetObjectItem(objItem, "对象继承");
            if (inheritedclass && cJSON_IsString(inheritedclass)) {
                oinfo.inheritedclass = inheritedclass->valuestring;
            }

            // 解析函数数组
            cJSON* functions = cJSON_GetObjectItem(objItem, "函数");
            if (functions && cJSON_IsArray(functions)) {
                for (int j = 0; j < cJSON_GetArraySize(functions); j++) {
                    cJSON* func = cJSON_GetArrayItem(functions, j);
                    if (!func) continue;

                    ParamInfo fi;
                    cJSON* name = cJSON_GetObjectItem(func, "名称");
                    cJSON* comment = cJSON_GetObjectItem(func, "注释");

                    if (name && cJSON_IsString(name)) fi.name = name->valuestring;
                    if (comment && cJSON_IsString(comment)) fi.comment = comment->valuestring;

                    oinfo.functions.push_back(fi);
                }
            }

            // 解析参数数组
            cJSON* params = cJSON_GetObjectItem(objItem, "参数");
            if (params && cJSON_IsArray(params)) {
                for (int k = 0; k < cJSON_GetArraySize(params); k++) {
                    cJSON* param = cJSON_GetArrayItem(params, k);
                    if (!param) continue;

                    ParamInfo pi;
                    cJSON* name = cJSON_GetObjectItem(param, "名称");
                    cJSON* comment = cJSON_GetObjectItem(param, "注释");

                    if (name && cJSON_IsString(name)) pi.name = name->valuestring;
                    if (comment && cJSON_IsString(comment)) pi.comment = comment->valuestring;

                    oinfo.params.push_back(pi);
                }
            }

            if (!oinfo.objectName.empty()) {
                mObjectList[oinfo.objectName] = oinfo;
            }
        }
    }

    cJSON_Delete(root);  // 正确释放内存

    return true;
}

ObjectInfo* LuaAnalyzer::getVariableInfo(std::string varName)
{
    if(mObjectList.empty() || varName == "")
        return NULL;

    std::map<std::string,ObjectInfo>::iterator iter = mObjectList.begin();
    for(;iter != mObjectList.end();++iter)
    {
        if((*iter).second.isInCreateFuncitons(varName))
            return &(*iter).second;
    }

    return NULL;
}

ObjectInfo* LuaAnalyzer::getInheritedObjectInfo(std::string InheritedObjectName)
{
    if(mObjectList.empty() || InheritedObjectName == "")
        return NULL;

    std::map<std::string,ObjectInfo>::iterator iter = mObjectList.begin();
    for(;iter != mObjectList.end();++iter)
    {
        if((*iter).second.objectName == InheritedObjectName)
            return &(*iter).second;
    }

    return NULL;
}

ObjectInfo* LuaAnalyzer::getObjectInfo(std::string objName)
{
    if(mObjectList.empty() || objName == "")
        return NULL;

    std::map<std::string,ObjectInfo>::iterator iter = mObjectList.begin();
    for(;iter != mObjectList.end();++iter)
    {
        int pos = objName.find((*iter).first);
        if(pos >= 0)
            return &(*iter).second;
    }

    return NULL;
}

std::string LuaAnalyzer::getParamInfo(std::string paramName)
{
    if(mObjectList.empty() || paramName == "")
        return "";

    std::map<std::string,ObjectInfo>::iterator iter = mObjectList.begin();
    for(;iter != mObjectList.end();++iter)
    {
        std::string decParams = (*iter).second.getParamInfo(paramName);
        if(decParams != "")
            return decParams;
    }

    return "";
}

// Load Lua script from string
void LuaAnalyzer::loadScriptFromString(const std::string& script)
{
    if(script == "") return;

    scriptContent.clear();
    std::istringstream iss(script);
    std::string line;
    while (std::getline(iss, line)) {
        scriptContent.push_back(line);
    }
}

// Perform analysis
void LuaAnalyzer::analyze()
{
    //clearResults();

    for (size_t i = 0; i < scriptContent.size(); ++i) {
        const auto& line = scriptContent[i];
        analyzeVariables(line, i + 1);  // Lines are 1-based
        analyzeFunctions(line, i + 1);
        analyzeObjects(line);
    }
}

void LuaAnalyzer::clearResults()
{
    variables.clear();
    functions.clear();
    objects.clear();
}

void LuaAnalyzer::analyzeVariables(const std::string& line, int lineNumber)
{
    try {
        // Match global variables (name = value)
        static std::regex globalVarPattern(R"((\w+)\s*=\s*(nil|\{[^\}]*\}|[^;]+))");
        // Match local variables (local name = value)
        static std::regex localVarPattern(R"(local\s+(\w+)\s*=\s*(nil|\{[^}]*\}|[^;]+))");

        std::smatch match;

        // Check for global variables
        if (std::regex_search(line, match, globalVarPattern)) {
            Variable var;
            var.name = match[1].str();
            var.type = (match[2].str() == "nil") ? "nil" : match[2].str();
            var.scope = "global";
            var.lineNumber = lineNumber;
            variables[var.name] = var;
        }

        // Check for local variables
        if (std::regex_search(line, match, localVarPattern)) {
            Variable var;
            var.name = match[1].str();
            var.type = (match[2].str() == "nil") ? "nil" : match[2].str();
            var.scope = "local";
            var.lineNumber = lineNumber;
            variables[var.name] = var;
        }
    } catch (const std::regex_error& e) {
        std::string error = e.what();
    }
}

void LuaAnalyzer::analyzeFunctions(const std::string& line, int lineNumber)
{
    try {
        // Match function declarations
        static std::regex funcPattern(R"(function\s+(\w+)\(([^)]*)\))");
        // Match local function declarations
        static std::regex localFuncPattern(R"(local\s+function\s+(\w+)\(([^)]*)\))");

        std::smatch match;

        // Check for global functions
        if (std::regex_search(line, match, funcPattern)) {
            Function func;
            func.name = match[1].str();
            func.lineNumber = lineNumber;

            // Split parameters
            std::string params = match[2].str();
            std::istringstream paramStream(params);
            std::string param;
            while (std::getline(paramStream, param, ',')) {
                func.parameters.push_back(param);
            }

            functions[func.name] = func;
        }

        // Check for local functions
        if (std::regex_search(line, match, localFuncPattern)) {
            Function func;
            func.name = match[1].str();
            func.lineNumber = lineNumber;

            // Split parameters
            std::string params = match[2].str();
            std::istringstream paramStream(params);
            std::string param;
            while (std::getline(paramStream, param, ',')) {
                func.parameters.push_back(param);
            }

            functions[func.name] = func;
        }
    } catch (const std::regex_error& e) {
        std::string error = e.what();
    }
}

void LuaAnalyzer::analyzeObjects(const std::string& line)
{
    try {
        // Match method calls (object:method(args))
        static std::regex methodCallPattern(R"((\w+):(\w+)\(([^)]*)\))");
        // Match object creation (var = Type.method(args))
        static std::regex objectCreationPattern(R"(\w+\s*=\s*(\w+)\.\w+\([^)]*\))");

        std::smatch match;

        // Check for method calls
        std::string::const_iterator searchStart(line.cbegin());
        while (std::regex_search(searchStart, line.cend(), match, methodCallPattern)) {
            std::string objName = match[1].str();
            std::string methodName = match[2].str();

            // Check if we already have this object
            bool found = false;
            std::map<std::string,Object>::iterator iterobj = objects.begin();
            for (;iterobj != objects.end();++iterobj) {
                if ((*iterobj).second.name == objName) {
                    if (std::find((*iterobj).second.methods.begin(), (*iterobj).second.methods.end(), methodName) == (*iterobj).second.methods.end()) {
                        (*iterobj).second.methods.push_back(methodName);
                    }
                    found = true;
                    break;
                }
            }

            if (!found) {
                Object obj;
                obj.name = objName;
                obj.type = "unknown";
                obj.methods.push_back(methodName);
                objects[obj.name] = obj;
            }

            searchStart = match.suffix().first;
        }

        // Check for object creation
        if (std::regex_search(line, match, objectCreationPattern)) {
            std::string typeName = match[1].str();

            // Check if we already have this type
            bool found = false;
            std::map<std::string,Object>::iterator iterobj = objects.begin();
            for (;iterobj != objects.end();++iterobj) {
                if ((*iterobj).second.name == typeName) {
                    found = true;
                    break;
                }
            }

            if (!found) {
                Object obj;
                obj.name = typeName;
                obj.type = "class/type";
                objects[obj.name] = obj;
            }
        }
    } catch (const std::regex_error& e) {
        std::string error = e.what();
    }
}

// Print analysis results
std::string LuaAnalyzer::printResults()
{
    std::string returnString;

    returnString+= "=== Variables ===\n";
    std::map<std::string,Variable>::iterator itervar = variables.begin();
    for(;itervar != variables.end();++itervar)
    {
        returnString+= ("Name: " + (*itervar).second.name
                    + ", Type: " + (*itervar).second.type
                    + ", Scope: " + (*itervar).second.scope+"\n");
    }

    returnString+= "\n=== Functions ===\n";
    std::map<std::string,Function>::iterator iterfun = functions.begin();
    for(;iterfun != functions.end();++iterfun)
    {
        returnString+= ("Name: " + (*iterfun).second.name + ", Parameters: ");
        for (const auto& param : (*iterfun).second.parameters) {
            returnString+= (param + " ");
        }
        returnString+="\n";
    }

    returnString+= "\n=== Objects ===\n";
    std::map<std::string,Object>::iterator iterobj = objects.begin();
    for(;iterobj != objects.end();++iterobj)
    {
        returnString+= ("Name: " + (*iterobj).second.name + ", Type: " + (*iterobj).second.type + "\n");
        returnString+= "Methods: ";
        for (const auto& method : (*iterobj).second.methods) {
            returnString+= (method + " ");
        }
        returnString+="\n";
    }

    return returnString;
}
